package com.eian.boot.common.id.service;

import com.eian.boot.common.id.IdHelper;
import com.eian.boot.common.id.enums.IdContentType;
import com.eian.boot.common.id.enums.IdTemplateType;
import com.eian.boot.common.id.exception.IdGenerationException;
import com.eian.boot.common.id.formatter.IdFormatter;
import com.eian.boot.common.id.mapper.IdFormatConfigMapper;
import com.eian.boot.common.id.model.IdFormatConfigEntity;
import com.eian.boot.common.id.model.PadPosition;
import com.eian.boot.common.id.obfuscator.IdObfuscator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ID格式化服务
 * 根据数据库配置动态格式化ID
 *
 * @author alex.meng
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IdFormatService {

    private final IdFormatConfigMapper formatConfigMapper;
    private final IdFormatter idFormatter;
    private final IdObfuscator idObfuscator;

    /**
     * 配置缓存（避免频繁查询数据库）
     */
    private final Map<String, IdFormatConfigEntity> configCache = new ConcurrentHashMap<>();

    /**
     * 根据配置生成并格式化ID（自动生成ID主体）
     *
     * @param bizType 业务类型
     * @return 格式化后的ID
     */
    public String generateIdByConfig(String bizType) {
        // 获取配置
        IdFormatConfigEntity config = getConfig(bizType);
        if (config == null) {
            throw new IdGenerationException("未找到业务类型[" + bizType + "]的格式配置，请在id_format_config表中初始化");
        }

        // 根据ID内容类型生成ID主体
        IdContentType contentType = IdContentType.fromCode(config.getIdContentType());
        Object idContent = generateIdContent(bizType, contentType);

        return formatIdInternal(bizType, config, idContent);
    }

    /**
     * 根据配置格式化ID（使用传入的原始ID）
     *
     * @param bizType 业务类型
     * @param rawId   原始ID
     * @return 格式化后的ID
     */
    public String formatIdByConfig(String bizType, long rawId) {
        // 获取配置
        IdFormatConfigEntity config = getConfig(bizType);
        if (config == null) {
            throw new IdGenerationException("未找到业务类型[" + bizType + "]的格式配置，请在id_format_config表中初始化");
        }

        return formatIdInternal(bizType, config, rawId);
    }

    /**
     * 内部格式化方法
     */
    private String formatIdInternal(String bizType, IdFormatConfigEntity config, Object idContent) {
        // 判断是否需要混淆
        Object contentToFormat = idContent;
        if (config.getUseObfuscate() != null && config.getUseObfuscate()) {
            if (idContent instanceof Long) {
                long obfuscated = idObfuscator.obfuscate((Long) idContent);
                log.debug("ID混淆：bizType={}, original={}, obfuscated={}", bizType, idContent, obfuscated);
                contentToFormat = obfuscated;
            } else if (idContent instanceof String) {
                try {
                    long originalId = Long.parseLong((String) idContent);
                    contentToFormat = idObfuscator.obfuscate(originalId);
                    log.debug("ID混淆：bizType={}, original={}, obfuscated={}", bizType, idContent, contentToFormat);
                } catch (NumberFormatException e) {
                    // 无法转换为Long，不进行混淆
                    log.warn("ID内容无法转换为Long，跳过混淆：bizType={}, content={}", bizType, idContent);
                }
            }
        }

        // 解析前缀（支持模板和固定值）
        String prefix = resolveTemplate(config.getPrefixTemplate(), config.getPrefix());

        // 解析后缀（支持模板和固定值）
        String suffix = resolveTemplate(config.getSuffixTemplate(), config.getSuffix());

        // 解析补位位置
        PadPosition padPosition = PadPosition.LEFT;
        if ("RIGHT".equalsIgnoreCase(config.getPadPosition())) {
            padPosition = PadPosition.RIGHT;
        }

        // 格式化ID
        char padChar = config.getPadChar() != null ? config.getPadChar() : '0';
        int length = config.getIdLength() != null ? config.getIdLength() : 0;

        String formattedId = idFormatter.formatId(
                contentToFormat,
                prefix,
                suffix,
                padChar,
                length,
                padPosition
        );

        log.debug("ID格式化成功：bizType={}, content={}, formattedId={}", bizType, idContent, formattedId);
        return formattedId;
    }

    /**
     * 根据ID内容类型生成ID
     */
    private Object generateIdContent(String bizType, IdContentType contentType) {
        return switch (contentType) {
            case SEGMENT -> IdHelper.nextSegmentId(bizType);
            case SEQUENCE -> IdHelper.nextSequence(bizType);
            case SNOWFLAKE -> IdHelper.snowflakeId();
            case UUID -> IdHelper.simpleUuid();
            case UUID_STANDARD -> IdHelper.uuid();
            case CUSTOM -> throw new IdGenerationException("ID内容类型为CUSTOM时，必须手动传入原始ID");
        };
    }

    /**
     * 解析模板（支持动态模板和固定值）
     */
    private String resolveTemplate(String templateType, String fixedValue) {
        IdTemplateType template = IdTemplateType.fromCode(templateType);
        if (template == IdTemplateType.FIXED) {
            // 使用固定值
            return fixedValue;
        } else {
            // 使用模板生成
            return template.generate();
        }
    }

    /**
     * 获取配置（带缓存）
     *
     * @param bizType 业务类型
     * @return 格式配置
     */
    private IdFormatConfigEntity getConfig(String bizType) {
        // 先从缓存获取
        IdFormatConfigEntity config = configCache.get(bizType);
        if (config != null) {
            return config;
        }

        // 从数据库查询
        config = formatConfigMapper.selectByBizType(bizType);
        if (config != null) {
            configCache.put(bizType, config);
        }
        return config;
    }

    /**
     * 清除配置缓存
     *
     * @param bizType 业务类型，null表示清除所有
     */
    public void clearCache(String bizType) {
        if (bizType == null) {
            configCache.clear();
            log.info("已清除所有ID格式配置缓存");
        } else {
            configCache.remove(bizType);
            log.info("已清除ID格式配置缓存：bizType={}", bizType);
        }
    }

    /**
     * 刷新配置缓存
     *
     * @param bizType 业务类型
     */
    public void refreshCache(String bizType) {
        IdFormatConfigEntity config = formatConfigMapper.selectByBizType(bizType);
        if (config != null) {
            configCache.put(bizType, config);
            log.info("已刷新ID格式配置缓存：bizType={}", bizType);
        } else {
            configCache.remove(bizType);
            log.warn("未找到业务类型[{}]的格式配置，已从缓存移除", bizType);
        }
    }
}

